package com.kool.kmqtt.server.packet;

import com.kool.kmqtt.server.ServerConfig;
import com.kool.kmqtt.server.exception.AppException;
import com.kool.kmqtt.server.exception.ErrorCode;
import com.kool.kmqtt.util.StringUtil;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 报文id生成器
 */
@Slf4j
public class PacketIdGenerator {
    private static ConcurrentHashMap<String, LinkedBlockingQueue<Integer>> ids = new ConcurrentHashMap<>();

    private static ReentrantLock lock = new ReentrantLock();

    public static void initClient(String clientId) {
        if (StringUtil.isEmpty(clientId)) {
            return;
        }
        lock.lock();
        try {
            if (ids.get(clientId) == null) {
                LinkedBlockingQueue<Integer> queue = new LinkedBlockingQueue<>();
                for (int i = 1; i < 1 + ServerConfig.getInstance().getPacketIdPoolSize(); i++) {
                    queue.offer(i);
                }
                ids.put(clientId, queue);
            }
        } catch (Exception e) {
            throw e;
        } finally {
            lock.unlock();
        }
    }

    /**
     * 生成报文id
     *
     * @param clientId
     * @return
     */
    public static int generateId(String clientId) {
        if (ids.get(clientId) == null) {
            initClient(clientId);
        }
        Integer nextId = ids.get(clientId).poll();
        if (nextId == null) {
            //客户端的报文id已用尽
            throw new AppException(ErrorCode.CHARSET_NOT_UTF8, clientId);
        }
        return nextId;
    }

    /**
     * 释放报文id
     *
     * @param clientId
     * @param packetId
     */
    public static void releaseId(String clientId, int packetId) {
        if (StringUtil.isEmpty(clientId)) {
            return;
        }
        if (ids.get(clientId) == null) {
            initClient(clientId);
            return;
        }
        ids.get(clientId).offer(packetId);
    }
}
